#include "Sigin.h"
#include "CryptoUtil.h"
#include <nlohmann/json.hpp>
#include <workflow/MySQLResult.h>
#include <map>
#include <string>
#include <iostream>
#include <functional>
using std::map;
using std::string;
using std::function;
using std::bind;
using namespace protocol;
using namespace wfrest;

using JSON = nlohmann::json;

Sigin::Sigin(wfrest::HttpServer & server)
:m_server(server)
{}

void Sigin::start(){
    signin_module();
}

struct SiginContext{
    HttpResp* resp;
    string username;
    string password;
    string token;
};

void Sigin::siginMysqlCallback(WFMySQLTask * mysqlTask){
    SiginContext * context = static_cast<SiginContext*>(series_of(mysqlTask)->get_context());
    if(mysqlTask->get_state() !=WFT_STATE_SUCCESS){
        context->resp->String("mysqlTask failed");
        return;
    }

    MySQLResultCursor cursor(mysqlTask->get_resp());

    if(cursor.get_cursor_status()==MYSQL_PACKET_ERROR){
        context->resp->String("error");
        return ;
    }

    if(cursor.get_cursor_status()==MYSQL_STATUS_GET_RESULT){
        map<string,MySQLCell> row;
        cursor.fetch_row(row);
        if(row.size()==0){
            context->resp->String("error");
            return;
        }
        string password = context->password;
        string salt = row["salt"].as_string();
        string encode_password = CryptoUtil::hash_password(password,salt);
        
        string storage_password = row["password"].as_string();
        
        #ifdef DEBUG
                std::cout<<"1111"<<"\n";
        #endif

        if(encode_password == storage_password){
            context->token = CryptoUtil::generate_token(context->username);
            #ifdef DEBUG
                std::cout<<context->token<<"\n";
            #endif

            JSON js;
            js["data"] = {{"Token",context->token},
                          {"Username",context->username},
                          {"Location","/static/view/home.html"}};

            context->resp->String(js.dump());
        }else{
            context->resp->String("error");           
        }
    }
}

void Sigin::signin_module(){

    function<void(WFMySQLTask *)> func = bind(&Sigin::siginMysqlCallback,this,std::placeholders::_1);

    m_server.POST("/user/signin",[func](const HttpReq* req, HttpResp* resp,SeriesWork* series){
        string username;
        string password;
        const map<string, string> &  prams = req->form_kv();
        for(const auto & [key,value]:prams){
            if(key == "username"){
                username = value;
            }
            if(key == "password"){
                password = value;
            }
        }

        #ifdef DEBUG
            std::cout<<username<<"\n";
            std::cout<<password<<"\n";
        #endif

        string sql = "select * from user_table where username = '"+username+"';";
        WFMySQLTask * mysqltask = WFTaskFactory::create_mysql_task("mysql://root:123@localhost/newCloudDisk",3,func);
        mysqltask->get_req()->set_query(sql);

        SiginContext * ctx = new SiginContext{resp,username,password,{}};
        series->set_context(ctx);
        
        series->set_callback([ctx](const SeriesWork *){
            delete ctx;
        });

        series->push_back(mysqltask);
    });    
}
